﻿using System;
using System.Collections.Generic;

using LinqToDB.SqlQuery;

namespace LinqToDB.Internal.SqlQuery
{
	internal static class SqlBinaryExpressionHelper
	{
		private static readonly Dictionary<(Type left, string operation, Type right), Type> _operationTypes = new()
		{
			// +
			{ (typeof(byte), "+", typeof(byte   )), ((byte)1 + (byte   )1).GetType() },
			{ (typeof(byte), "+", typeof(sbyte  )), ((byte)1 + (sbyte  )1).GetType() },
			{ (typeof(byte), "+", typeof(short  )), ((byte)1 + (short  )1).GetType() },
			{ (typeof(byte), "+", typeof(ushort )), ((byte)1 + (ushort )1).GetType() },
			{ (typeof(byte), "+", typeof(int    )), ((byte)1 + (int    )1).GetType() },
			{ (typeof(byte), "+", typeof(uint   )), ((byte)1 + (uint   )1).GetType() },
			{ (typeof(byte), "+", typeof(long   )), ((byte)1 + (long   )1).GetType() },
			{ (typeof(byte), "+", typeof(ulong  )), ((byte)1 + (ulong  )1).GetType() },
			{ (typeof(byte), "+", typeof(decimal)), ((byte)1 + (decimal)1).GetType() },
			{ (typeof(byte), "+", typeof(double )), ((byte)1 + (double )1).GetType() },
			{ (typeof(byte), "+", typeof(float  )), ((byte)1 + (float  )1).GetType() },
			{ (typeof(byte), "+", typeof(char   )), ((byte)1 + (char   )1).GetType() },

			{ (typeof(sbyte), "+", typeof(byte   )), ((sbyte)1 + (byte   )1).GetType() },
			{ (typeof(sbyte), "+", typeof(sbyte  )), ((sbyte)1 + (sbyte  )1).GetType() },
			{ (typeof(sbyte), "+", typeof(short  )), ((sbyte)1 + (short  )1).GetType() },
			{ (typeof(sbyte), "+", typeof(ushort )), ((sbyte)1 + (ushort )1).GetType() },
			{ (typeof(sbyte), "+", typeof(int    )), ((sbyte)1 + (int    )1).GetType() },
			{ (typeof(sbyte), "+", typeof(uint   )), ((sbyte)1 + (uint   )1).GetType() },
			{ (typeof(sbyte), "+", typeof(long   )), ((sbyte)1 + (long   )1).GetType() },
			//{ (typeof(sbyte), "+", typeof(ulong  )), ((sbyte)1 + (ulong  )1).GetType() },
			{ (typeof(sbyte), "+", typeof(decimal)), ((sbyte)1 + (decimal)1).GetType() },
			{ (typeof(sbyte), "+", typeof(double )), ((sbyte)1 + (double )1).GetType() },
			{ (typeof(sbyte), "+", typeof(float  )), ((sbyte)1 + (float  )1).GetType() },
			{ (typeof(sbyte), "+", typeof(char   )), ((sbyte)1 + (char   )1).GetType() },

			{ (typeof(short), "+", typeof(byte   )), ((short)1 + (byte   )1).GetType() },
			{ (typeof(short), "+", typeof(sbyte  )), ((short)1 + (sbyte  )1).GetType() },
			{ (typeof(short), "+", typeof(short  )), ((short)1 + (short  )1).GetType() },
			{ (typeof(short), "+", typeof(ushort )), ((short)1 + (ushort )1).GetType() },
			{ (typeof(short), "+", typeof(int    )), ((short)1 + (int    )1).GetType() },
			{ (typeof(short), "+", typeof(uint   )), ((short)1 + (uint   )1).GetType() },
			{ (typeof(short), "+", typeof(long   )), ((short)1 + (long   )1).GetType() },
			//{ (typeof(short), "+", typeof(ulong  )), ((short)1 + (ulong  )1).GetType() },
			{ (typeof(short), "+", typeof(decimal)), ((short)1 + (decimal)1).GetType() },
			{ (typeof(short), "+", typeof(double )), ((short)1 + (double )1).GetType() },
			{ (typeof(short), "+", typeof(float  )), ((short)1 + (float  )1).GetType() },
			{ (typeof(short), "+", typeof(char   )), ((short)1 + (char   )1).GetType() },

			{ (typeof(ushort), "+", typeof(byte   )), ((ushort)1 + (byte   )1).GetType() },
			{ (typeof(ushort), "+", typeof(sbyte  )), ((ushort)1 + (sbyte  )1).GetType() },
			{ (typeof(ushort), "+", typeof(short  )), ((ushort)1 + (short  )1).GetType() },
			{ (typeof(ushort), "+", typeof(ushort )), ((ushort)1 + (ushort )1).GetType() },
			{ (typeof(ushort), "+", typeof(int    )), ((ushort)1 + (int    )1).GetType() },
			{ (typeof(ushort), "+", typeof(uint   )), ((ushort)1 + (uint   )1).GetType() },
			{ (typeof(ushort), "+", typeof(long   )), ((ushort)1 + (long   )1).GetType() },
			{ (typeof(ushort), "+", typeof(ulong  )), ((ushort)1 + (ulong  )1).GetType() },
			{ (typeof(ushort), "+", typeof(decimal)), ((ushort)1 + (decimal)1).GetType() },
			{ (typeof(ushort), "+", typeof(double )), ((ushort)1 + (double )1).GetType() },
			{ (typeof(ushort), "+", typeof(float  )), ((ushort)1 + (float  )1).GetType() },
			{ (typeof(ushort), "+", typeof(char   )), ((ushort)1 + (char   )1).GetType() },

			{ (typeof(int), "+", typeof(byte   )), ((int)1 + (byte   )1).GetType() },
			{ (typeof(int), "+", typeof(sbyte  )), ((int)1 + (sbyte  )1).GetType() },
			{ (typeof(int), "+", typeof(short  )), ((int)1 + (short  )1).GetType() },
			{ (typeof(int), "+", typeof(ushort )), ((int)1 + (ushort )1).GetType() },
			{ (typeof(int), "+", typeof(int    )), ((int)1 + (int    )1).GetType() },
			{ (typeof(int), "+", typeof(uint   )), ((int)1 + (uint   )1).GetType() },
			{ (typeof(int), "+", typeof(long   )), ((int)1 + (long   )1).GetType() },
			{ (typeof(int), "+", typeof(ulong  )), ((int)1 + (ulong  )1).GetType() },
			{ (typeof(int), "+", typeof(decimal)), ((int)1 + (decimal)1).GetType() },
			{ (typeof(int), "+", typeof(double )), ((int)1 + (double )1).GetType() },
			{ (typeof(int), "+", typeof(float  )), ((int)1 + (float  )1).GetType() },
			{ (typeof(int), "+", typeof(char   )), ((int)1 + (char   )1).GetType() },

			{ (typeof(uint), "+", typeof(byte   )), ((uint)1 + (byte   )1).GetType() },
			{ (typeof(uint), "+", typeof(sbyte  )), ((uint)1 + (sbyte  )1).GetType() },
			{ (typeof(uint), "+", typeof(short  )), ((uint)1 + (short  )1).GetType() },
			{ (typeof(uint), "+", typeof(ushort )), ((uint)1 + (ushort )1).GetType() },
			{ (typeof(uint), "+", typeof(int    )), ((uint)1 + (int    )1).GetType() },
			{ (typeof(uint), "+", typeof(uint   )), ((uint)1 + (uint   )1).GetType() },
			{ (typeof(uint), "+", typeof(long   )), ((uint)1 + (long   )1).GetType() },
			{ (typeof(uint), "+", typeof(ulong  )), ((uint)1 + (ulong  )1).GetType() },
			{ (typeof(uint), "+", typeof(decimal)), ((uint)1 + (decimal)1).GetType() },
			{ (typeof(uint), "+", typeof(double )), ((uint)1 + (double )1).GetType() },
			{ (typeof(uint), "+", typeof(float  )), ((uint)1 + (float  )1).GetType() },
			{ (typeof(uint), "+", typeof(char   )), ((uint)1 + (char   )1).GetType() },

			{ (typeof(long), "+", typeof(byte   )), ((long)1 + (byte   )1).GetType() },
			{ (typeof(long), "+", typeof(sbyte  )), ((long)1 + (sbyte  )1).GetType() },
			{ (typeof(long), "+", typeof(short  )), ((long)1 + (short  )1).GetType() },
			{ (typeof(long), "+", typeof(ushort )), ((long)1 + (ushort )1).GetType() },
			{ (typeof(long), "+", typeof(int    )), ((long)1 + (int    )1).GetType() },
			{ (typeof(long), "+", typeof(uint   )), ((long)1 + (uint   )1).GetType() },
			{ (typeof(long), "+", typeof(long   )), ((long)1 + (long   )1).GetType() },
			{ (typeof(long), "+", typeof(ulong  )), ((long)1 + (ulong  )1).GetType() },
			{ (typeof(long), "+", typeof(decimal)), ((long)1 + (decimal)1).GetType() },
			{ (typeof(long), "+", typeof(double )), ((long)1 + (double )1).GetType() },
			{ (typeof(long), "+", typeof(float  )), ((long)1 + (float  )1).GetType() },
			{ (typeof(long), "+", typeof(char   )), ((long)1 + (char   )1).GetType() },

			{ (typeof(ulong), "+", typeof(byte   )), ((ulong)1 + (byte   )1).GetType() },
			//{ (typeof(ulong), "+", typeof(sbyte  )), ((ulong)1 + (sbyte  )1).GetType() },
			//{ (typeof(ulong), "+", typeof(short  )), ((ulong)1 + (short  )1).GetType() },
			{ (typeof(ulong), "+", typeof(ushort )), ((ulong)1 + (ushort )1).GetType() },
			{ (typeof(ulong), "+", typeof(int    )), ((ulong)1 + (int    )1).GetType() },
			{ (typeof(ulong), "+", typeof(uint   )), ((ulong)1 + (uint   )1).GetType() },
			{ (typeof(ulong), "+", typeof(long   )), ((ulong)1 + (long   )1).GetType() },
			{ (typeof(ulong), "+", typeof(ulong  )), ((ulong)1 + (ulong  )1).GetType() },
			{ (typeof(ulong), "+", typeof(decimal)), ((ulong)1 + (decimal)1).GetType() },
			{ (typeof(ulong), "+", typeof(double )), ((ulong)1 + (double )1).GetType() },
			{ (typeof(ulong), "+", typeof(float  )), ((ulong)1 + (float  )1).GetType() },
			{ (typeof(ulong), "+", typeof(char   )), ((ulong)1 + (char   )1).GetType() },

			{ (typeof(decimal), "+", typeof(byte   )), ((decimal)1 + (byte   )1).GetType() },
			{ (typeof(decimal), "+", typeof(sbyte  )), ((decimal)1 + (sbyte  )1).GetType() },
			{ (typeof(decimal), "+", typeof(short  )), ((decimal)1 + (short  )1).GetType() },
			{ (typeof(decimal), "+", typeof(ushort )), ((decimal)1 + (ushort )1).GetType() },
			{ (typeof(decimal), "+", typeof(int    )), ((decimal)1 + (int    )1).GetType() },
			{ (typeof(decimal), "+", typeof(uint   )), ((decimal)1 + (uint   )1).GetType() },
			{ (typeof(decimal), "+", typeof(long   )), ((decimal)1 + (long   )1).GetType() },
			{ (typeof(decimal), "+", typeof(ulong  )), ((decimal)1 + (ulong  )1).GetType() },
			{ (typeof(decimal), "+", typeof(decimal)), ((decimal)1 + (decimal)1).GetType() },
			//{ (typeof(decimal), "+", typeof(double )), ((decimal)1 + (double )1).GetType() },
			//{ (typeof(decimal), "+", typeof(float  )), ((decimal)1 + (float  )1).GetType() },
			{ (typeof(decimal), "+", typeof(char   )), ((decimal)1 + (char   )1).GetType() },

			{ (typeof(double), "+", typeof(byte   )), ((double)1 + (byte   )1).GetType() },
			{ (typeof(double), "+", typeof(sbyte  )), ((double)1 + (sbyte  )1).GetType() },
			{ (typeof(double), "+", typeof(short  )), ((double)1 + (short  )1).GetType() },
			{ (typeof(double), "+", typeof(ushort )), ((double)1 + (ushort )1).GetType() },
			{ (typeof(double), "+", typeof(int    )), ((double)1 + (int    )1).GetType() },
			{ (typeof(double), "+", typeof(uint   )), ((double)1 + (uint   )1).GetType() },
			{ (typeof(double), "+", typeof(long   )), ((double)1 + (long   )1).GetType() },
			{ (typeof(double), "+", typeof(ulong  )), ((double)1 + (ulong  )1).GetType() },
			//{ (typeof(double), "+", typeof(decimal)), ((double)1 + (decimal)1).GetType() },
			{ (typeof(double), "+", typeof(double )), ((double)1 + (double )1).GetType() },
			{ (typeof(double), "+", typeof(float  )), ((double)1 + (float  )1).GetType() },
			{ (typeof(double), "+", typeof(char   )), ((double)1 + (char   )1).GetType() },

			{ (typeof(float), "+", typeof(byte   )), ((float)1 + (byte   )1).GetType() },
			{ (typeof(float), "+", typeof(sbyte  )), ((float)1 + (sbyte  )1).GetType() },
			{ (typeof(float), "+", typeof(short  )), ((float)1 + (short  )1).GetType() },
			{ (typeof(float), "+", typeof(ushort )), ((float)1 + (ushort )1).GetType() },
			{ (typeof(float), "+", typeof(int    )), ((float)1 + (int    )1).GetType() },
			{ (typeof(float), "+", typeof(uint   )), ((float)1 + (uint   )1).GetType() },
			{ (typeof(float), "+", typeof(long   )), ((float)1 + (long   )1).GetType() },
			{ (typeof(float), "+", typeof(ulong  )), ((float)1 + (ulong  )1).GetType() },
			//{ (typeof(float), "+", typeof(decimal)), ((float)1 + (decimal)1).GetType() },
			{ (typeof(float), "+", typeof(double )), ((float)1 + (double )1).GetType() },
			{ (typeof(float), "+", typeof(float  )), ((float)1 + (float  )1).GetType() },
			{ (typeof(float), "+", typeof(char   )), ((float)1 + (char   )1).GetType() },

			{ (typeof(char), "+", typeof(byte   )), ((char)1 + (byte   )1).GetType() },
			{ (typeof(char), "+", typeof(sbyte  )), ((char)1 + (sbyte  )1).GetType() },
			{ (typeof(char), "+", typeof(short  )), ((char)1 + (short  )1).GetType() },
			{ (typeof(char), "+", typeof(ushort )), ((char)1 + (ushort )1).GetType() },
			{ (typeof(char), "+", typeof(int    )), ((char)1 + (int    )1).GetType() },
			{ (typeof(char), "+", typeof(uint   )), ((char)1 + (uint   )1).GetType() },
			{ (typeof(char), "+", typeof(long   )), ((char)1 + (long   )1).GetType() },
			{ (typeof(char), "+", typeof(ulong  )), ((char)1 + (ulong  )1).GetType() },
			{ (typeof(char), "+", typeof(decimal)), ((char)1 + (decimal)1).GetType() },
			{ (typeof(char), "+", typeof(double )), ((char)1 + (double )1).GetType() },
			{ (typeof(char), "+", typeof(float  )), ((char)1 + (float  )1).GetType() },
			{ (typeof(char), "+", typeof(char   )), ((char)1 + (char   )1).GetType() },

			// -
			{ (typeof(byte), "-", typeof(byte   )), ((byte)1 - (byte   )1).GetType() },
			{ (typeof(byte), "-", typeof(sbyte  )), ((byte)1 - (sbyte  )1).GetType() },
			{ (typeof(byte), "-", typeof(short  )), ((byte)1 - (short  )1).GetType() },
			{ (typeof(byte), "-", typeof(ushort )), ((byte)1 - (ushort )1).GetType() },
			{ (typeof(byte), "-", typeof(int    )), ((byte)1 - (int    )1).GetType() },
			{ (typeof(byte), "-", typeof(uint   )), ((byte)1 - (uint   )1).GetType() },
			{ (typeof(byte), "-", typeof(long   )), ((byte)1 - (long   )1).GetType() },
			{ (typeof(byte), "-", typeof(ulong  )), ((byte)1 - (ulong  )1).GetType() },
			{ (typeof(byte), "-", typeof(decimal)), ((byte)1 - (decimal)1).GetType() },
			{ (typeof(byte), "-", typeof(double )), ((byte)1 - (double )1).GetType() },
			{ (typeof(byte), "-", typeof(float  )), ((byte)1 - (float  )1).GetType() },
			{ (typeof(byte), "-", typeof(char   )), ((byte)1 - (char   )1).GetType() },

			{ (typeof(sbyte), "-", typeof(byte   )), ((sbyte)1 - (byte   )1).GetType() },
			{ (typeof(sbyte), "-", typeof(sbyte  )), ((sbyte)1 - (sbyte  )1).GetType() },
			{ (typeof(sbyte), "-", typeof(short  )), ((sbyte)1 - (short  )1).GetType() },
			{ (typeof(sbyte), "-", typeof(ushort )), ((sbyte)1 - (ushort )1).GetType() },
			{ (typeof(sbyte), "-", typeof(int    )), ((sbyte)1 - (int    )1).GetType() },
			{ (typeof(sbyte), "-", typeof(uint   )), ((sbyte)1 - (uint   )1).GetType() },
			{ (typeof(sbyte), "-", typeof(long   )), ((sbyte)1 - (long   )1).GetType() },
			//{ (typeof(sbyte), "-", typeof(ulong  )), ((sbyte)1 - (ulong  )1).GetType() },
			{ (typeof(sbyte), "-", typeof(decimal)), ((sbyte)1 - (decimal)1).GetType() },
			{ (typeof(sbyte), "-", typeof(double )), ((sbyte)1 - (double )1).GetType() },
			{ (typeof(sbyte), "-", typeof(float  )), ((sbyte)1 - (float  )1).GetType() },
			{ (typeof(sbyte), "-", typeof(char   )), ((sbyte)1 - (char   )1).GetType() },

			{ (typeof(short), "-", typeof(byte   )), ((short)1 - (byte   )1).GetType() },
			{ (typeof(short), "-", typeof(sbyte  )), ((short)1 - (sbyte  )1).GetType() },
			{ (typeof(short), "-", typeof(short  )), ((short)1 - (short  )1).GetType() },
			{ (typeof(short), "-", typeof(ushort )), ((short)1 - (ushort )1).GetType() },
			{ (typeof(short), "-", typeof(int    )), ((short)1 - (int    )1).GetType() },
			{ (typeof(short), "-", typeof(uint   )), ((short)1 - (uint   )1).GetType() },
			{ (typeof(short), "-", typeof(long   )), ((short)1 - (long   )1).GetType() },
			//{ (typeof(short), "-", typeof(ulong  )), ((short)1 - (ulong  )1).GetType() },
			{ (typeof(short), "-", typeof(decimal)), ((short)1 - (decimal)1).GetType() },
			{ (typeof(short), "-", typeof(double )), ((short)1 - (double )1).GetType() },
			{ (typeof(short), "-", typeof(float  )), ((short)1 - (float  )1).GetType() },
			{ (typeof(short), "-", typeof(char   )), ((short)1 - (char   )1).GetType() },

			{ (typeof(ushort), "-", typeof(byte   )), ((ushort)1 - (byte   )1).GetType() },
			{ (typeof(ushort), "-", typeof(sbyte  )), ((ushort)1 - (sbyte  )1).GetType() },
			{ (typeof(ushort), "-", typeof(short  )), ((ushort)1 - (short  )1).GetType() },
			{ (typeof(ushort), "-", typeof(ushort )), ((ushort)1 - (ushort )1).GetType() },
			{ (typeof(ushort), "-", typeof(int    )), ((ushort)1 - (int    )1).GetType() },
			{ (typeof(ushort), "-", typeof(uint   )), ((ushort)1 - (uint   )1).GetType() },
			{ (typeof(ushort), "-", typeof(long   )), ((ushort)1 - (long   )1).GetType() },
			{ (typeof(ushort), "-", typeof(ulong  )), ((ushort)1 - (ulong  )1).GetType() },
			{ (typeof(ushort), "-", typeof(decimal)), ((ushort)1 - (decimal)1).GetType() },
			{ (typeof(ushort), "-", typeof(double )), ((ushort)1 - (double )1).GetType() },
			{ (typeof(ushort), "-", typeof(float  )), ((ushort)1 - (float  )1).GetType() },
			{ (typeof(ushort), "-", typeof(char   )), ((ushort)1 - (char   )1).GetType() },

			{ (typeof(int), "-", typeof(byte   )), ((int)1 - (byte   )1).GetType() },
			{ (typeof(int), "-", typeof(sbyte  )), ((int)1 - (sbyte  )1).GetType() },
			{ (typeof(int), "-", typeof(short  )), ((int)1 - (short  )1).GetType() },
			{ (typeof(int), "-", typeof(ushort )), ((int)1 - (ushort )1).GetType() },
			{ (typeof(int), "-", typeof(int    )), ((int)1 - (int    )1).GetType() },
			{ (typeof(int), "-", typeof(uint   )), ((int)1 - (uint   )1).GetType() },
			{ (typeof(int), "-", typeof(long   )), ((int)1 - (long   )1).GetType() },
			{ (typeof(int), "-", typeof(ulong  )), ((int)1 - (ulong  )1).GetType() },
			{ (typeof(int), "-", typeof(decimal)), ((int)1 - (decimal)1).GetType() },
			{ (typeof(int), "-", typeof(double )), ((int)1 - (double )1).GetType() },
			{ (typeof(int), "-", typeof(float  )), ((int)1 - (float  )1).GetType() },
			{ (typeof(int), "-", typeof(char   )), ((int)1 - (char   )1).GetType() },

			{ (typeof(uint), "-", typeof(byte   )), ((uint)1 - (byte   )1).GetType() },
			{ (typeof(uint), "-", typeof(sbyte  )), ((uint)1 - (sbyte  )1).GetType() },
			{ (typeof(uint), "-", typeof(short  )), ((uint)1 - (short  )1).GetType() },
			{ (typeof(uint), "-", typeof(ushort )), ((uint)1 - (ushort )1).GetType() },
			{ (typeof(uint), "-", typeof(int    )), ((uint)1 - (int    )1).GetType() },
			{ (typeof(uint), "-", typeof(uint   )), ((uint)1 - (uint   )1).GetType() },
			{ (typeof(uint), "-", typeof(long   )), ((uint)1 - (long   )1).GetType() },
			{ (typeof(uint), "-", typeof(ulong  )), ((uint)1 - (ulong  )1).GetType() },
			{ (typeof(uint), "-", typeof(decimal)), ((uint)1 - (decimal)1).GetType() },
			{ (typeof(uint), "-", typeof(double )), ((uint)1 - (double )1).GetType() },
			{ (typeof(uint), "-", typeof(float  )), ((uint)1 - (float  )1).GetType() },
			{ (typeof(uint), "-", typeof(char   )), ((uint)1 - (char   )1).GetType() },

			{ (typeof(long), "-", typeof(byte   )), ((long)1 - (byte   )1).GetType() },
			{ (typeof(long), "-", typeof(sbyte  )), ((long)1 - (sbyte  )1).GetType() },
			{ (typeof(long), "-", typeof(short  )), ((long)1 - (short  )1).GetType() },
			{ (typeof(long), "-", typeof(ushort )), ((long)1 - (ushort )1).GetType() },
			{ (typeof(long), "-", typeof(int    )), ((long)1 - (int    )1).GetType() },
			{ (typeof(long), "-", typeof(uint   )), ((long)1 - (uint   )1).GetType() },
			{ (typeof(long), "-", typeof(long   )), ((long)1 - (long   )1).GetType() },
			{ (typeof(long), "-", typeof(ulong  )), ((long)1 - (ulong  )1).GetType() },
			{ (typeof(long), "-", typeof(decimal)), ((long)1 - (decimal)1).GetType() },
			{ (typeof(long), "-", typeof(double )), ((long)1 - (double )1).GetType() },
			{ (typeof(long), "-", typeof(float  )), ((long)1 - (float  )1).GetType() },
			{ (typeof(long), "-", typeof(char   )), ((long)1 - (char   )1).GetType() },

			{ (typeof(ulong), "-", typeof(byte   )), ((ulong)1 - (byte   )1).GetType() },
			//{ (typeof(ulong), "-", typeof(sbyte  )), ((ulong)1 - (sbyte  )1).GetType() },
			//{ (typeof(ulong), "-", typeof(short  )), ((ulong)1 - (short  )1).GetType() },
			{ (typeof(ulong), "-", typeof(ushort )), ((ulong)1 - (ushort )1).GetType() },
			{ (typeof(ulong), "-", typeof(int    )), ((ulong)1 - (int    )1).GetType() },
			{ (typeof(ulong), "-", typeof(uint   )), ((ulong)1 - (uint   )1).GetType() },
			{ (typeof(ulong), "-", typeof(long   )), ((ulong)1 - (long   )1).GetType() },
			{ (typeof(ulong), "-", typeof(ulong  )), ((ulong)1 - (ulong  )1).GetType() },
			{ (typeof(ulong), "-", typeof(decimal)), ((ulong)1 - (decimal)1).GetType() },
			{ (typeof(ulong), "-", typeof(double )), ((ulong)1 - (double )1).GetType() },
			{ (typeof(ulong), "-", typeof(float  )), ((ulong)1 - (float  )1).GetType() },
			{ (typeof(ulong), "-", typeof(char   )), ((ulong)1 - (char   )1).GetType() },

			{ (typeof(decimal), "-", typeof(byte   )), ((decimal)1 - (byte   )1).GetType() },
			{ (typeof(decimal), "-", typeof(sbyte  )), ((decimal)1 - (sbyte  )1).GetType() },
			{ (typeof(decimal), "-", typeof(short  )), ((decimal)1 - (short  )1).GetType() },
			{ (typeof(decimal), "-", typeof(ushort )), ((decimal)1 - (ushort )1).GetType() },
			{ (typeof(decimal), "-", typeof(int    )), ((decimal)1 - (int    )1).GetType() },
			{ (typeof(decimal), "-", typeof(uint   )), ((decimal)1 - (uint   )1).GetType() },
			{ (typeof(decimal), "-", typeof(long   )), ((decimal)1 - (long   )1).GetType() },
			{ (typeof(decimal), "-", typeof(ulong  )), ((decimal)1 - (ulong  )1).GetType() },
			{ (typeof(decimal), "-", typeof(decimal)), ((decimal)1 - (decimal)1).GetType() },
			//{ (typeof(decimal), "-", typeof(double )), ((decimal)1 - (double )1).GetType() },
			//{ (typeof(decimal), "-", typeof(float  )), ((decimal)1 - (float  )1).GetType() },
			{ (typeof(decimal), "-", typeof(char   )), ((decimal)1 - (char   )1).GetType() },

			{ (typeof(double), "-", typeof(byte   )), ((double)1 - (byte   )1).GetType() },
			{ (typeof(double), "-", typeof(sbyte  )), ((double)1 - (sbyte  )1).GetType() },
			{ (typeof(double), "-", typeof(short  )), ((double)1 - (short  )1).GetType() },
			{ (typeof(double), "-", typeof(ushort )), ((double)1 - (ushort )1).GetType() },
			{ (typeof(double), "-", typeof(int    )), ((double)1 - (int    )1).GetType() },
			{ (typeof(double), "-", typeof(uint   )), ((double)1 - (uint   )1).GetType() },
			{ (typeof(double), "-", typeof(long   )), ((double)1 - (long   )1).GetType() },
			{ (typeof(double), "-", typeof(ulong  )), ((double)1 - (ulong  )1).GetType() },
			//{ (typeof(double), "-", typeof(decimal)), ((double)1 - (decimal)1).GetType() },
			{ (typeof(double), "-", typeof(double )), ((double)1 - (double )1).GetType() },
			{ (typeof(double), "-", typeof(float  )), ((double)1 - (float  )1).GetType() },
			{ (typeof(double), "-", typeof(char   )), ((double)1 - (char   )1).GetType() },

			{ (typeof(float), "-", typeof(byte   )), ((float)1 - (byte   )1).GetType() },
			{ (typeof(float), "-", typeof(sbyte  )), ((float)1 - (sbyte  )1).GetType() },
			{ (typeof(float), "-", typeof(short  )), ((float)1 - (short  )1).GetType() },
			{ (typeof(float), "-", typeof(ushort )), ((float)1 - (ushort )1).GetType() },
			{ (typeof(float), "-", typeof(int    )), ((float)1 - (int    )1).GetType() },
			{ (typeof(float), "-", typeof(uint   )), ((float)1 - (uint   )1).GetType() },
			{ (typeof(float), "-", typeof(long   )), ((float)1 - (long   )1).GetType() },
			{ (typeof(float), "-", typeof(ulong  )), ((float)1 - (ulong  )1).GetType() },
			//{ (typeof(float), "-", typeof(decimal)), ((float)1 - (decimal)1).GetType() },
			{ (typeof(float), "-", typeof(double )), ((float)1 - (double )1).GetType() },
			{ (typeof(float), "-", typeof(float  )), ((float)1 - (float  )1).GetType() },
			{ (typeof(float), "-", typeof(char   )), ((float)1 - (char   )1).GetType() },

			{ (typeof(char), "-", typeof(byte   )), ((char)1 - (byte   )1).GetType() },
			{ (typeof(char), "-", typeof(sbyte  )), ((char)1 - (sbyte  )1).GetType() },
			{ (typeof(char), "-", typeof(short  )), ((char)1 - (short  )1).GetType() },
			{ (typeof(char), "-", typeof(ushort )), ((char)1 - (ushort )1).GetType() },
			{ (typeof(char), "-", typeof(int    )), ((char)1 - (int    )1).GetType() },
			{ (typeof(char), "-", typeof(uint   )), ((char)1 - (uint   )1).GetType() },
			{ (typeof(char), "-", typeof(long   )), ((char)1 - (long   )1).GetType() },
			{ (typeof(char), "-", typeof(ulong  )), ((char)1 - (ulong  )1).GetType() },
			{ (typeof(char), "-", typeof(decimal)), ((char)1 - (decimal)1).GetType() },
			{ (typeof(char), "-", typeof(double )), ((char)1 - (double )1).GetType() },
			{ (typeof(char), "-", typeof(float  )), ((char)1 - (float  )1).GetType() },
			{ (typeof(char), "-", typeof(char   )), ((char)1 - (char   )1).GetType() },
		};

		public static Type? TryGetBinaryType(Type left, string operation, Type right)
		{
			return _operationTypes.TryGetValue((left, operation, right), out var type) ? type : null;
		}

		public static SqlBinaryExpression CreateWithTypeInferred(Type defaultType, ISqlExpression expr1, string operation, ISqlExpression expr2, int precedence = Precedence.Unknown)
		{
			var type = expr1.SystemType == null || expr2.SystemType == null
				? defaultType
				: (TryGetBinaryType(expr1.SystemType, operation, expr2.SystemType) ?? defaultType);

			return new SqlBinaryExpression(type, expr1, operation, expr2, precedence);
		}
	}
}
